using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using Microsoft.Win32;

namespace Universe.WinForms
{
    public class WindowsVersionInfo
    {
        
        
        public static Version InternetExplorerVersion
        {
            get
            {
                using (RegistryKey ie = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\Internet Explorer", false))
                {
                    if (ie != null)
                    {
                        string rawVer = ie.GetValue("Version") as string;
                        if (rawVer != null)
                        {
                            Version ret = new Version(rawVer);
                            return ret;
                        }
                    }
                }

                return null;
            }
        }

        public static readonly ComVersionInfo ComInfo = ComVersionInfo.Instance;
        
        public static FileVersionInfo GetComFileVersion(string progId)
        {
            ComVersionDescription d = GetComVersionByProgID(progId);
            return d == null ? null : d.FileVersion;
        }
        
        public class ComVersionInfo
        {
            private ComVersionInfo()
            {
            }
            
            internal static readonly ComVersionInfo Instance = new ComVersionInfo();
            
            public Version this[string progId]
            {
                get
                {
                    ComVersionDescription d = GetComVersionByProgID(progId);
                    return d == null ? null : new Version(ExtractVersion(d.FileVersion.FileVersion));
                }
            }
        }
        
        static string ExtractVersion(string rawVersion)
        {
            StringBuilder ret = new StringBuilder();
            foreach(char c in rawVersion)
            {
                const string allow = "0123456789.";
                bool isOK = allow.IndexOf(c) >= 0;
                if (isOK)
                    ret.Append(c);
                else break;
            }

            return ret.ToString();
        }
        
        class ComVersionDescription
        {
            public readonly Version Version;
            public readonly FileVersionInfo FileVersion;


            public ComVersionDescription(Version version, FileVersionInfo fileInfo)
            {
                Version = version;
                FileVersion = fileInfo;
            }
        }
        
        static ComVersionDescription GetComVersionByProgID(string progId)
        {
            using (RegistryKey reg1 = Registry.ClassesRoot.OpenSubKey(progId + "\\CLSID", false))
            {
                if (reg1 != null)
                {

                    string rawGuid = reg1.GetValue(string.Empty) as string;
                    if (rawGuid != null)
                    {
                        using(RegistryKey reg2 = Registry.ClassesRoot.OpenSubKey("CLSID\\" + rawGuid + "\\LocalServer32", false))
                        {
                            if (reg2 != null)
                            {
                                string rawDll = reg2.GetValue(string.Empty) as string;
                                if (rawDll != null)
                                {
                                    rawDll = rawDll.TrimStart();
                                    if (rawDll.StartsWith("\""))
                                    {
                                        int index = rawDll.IndexOf("\"", 1);
                                        if (index > 2)
                                            rawDll = rawDll.Substring(1, index - 1);
                                        else
                                            return null;
                                    }
                                    else
                                    {
                                        string[] arr = rawDll.Split(' ');
                                        if (arr.Length > 0)
                                            rawDll = arr[0];
                                        else
                                            return null;
                                    }

                                    FileVersionInfo fv = FileVersionInfo.GetVersionInfo(rawDll);
                                    if (fv != null)
                                    {
                                        return new ComVersionDescription(null, fv);
                                    }
                                }
                            }
                        }
                    }
                }
            }

            return null;
            
        }
    }
}
